package cc.rengu.igas.channel.nucc.core.packswitch;


import cc.rengu.igas.channel.nucc.common.constant.NuccParamConstant;
import cc.rengu.igas.channel.nucc.common.constant.NuccTreeNodeConstant;
import cc.rengu.igas.channel.nucc.common.constant.NuccTxnNumConstant;
import cc.rengu.igas.channel.nucc.core.realize.NuccEncSignService;
import cc.rengu.igas.channel.nucc.core.realize.impl.NuccEncSignServiceImpl;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.base.TimeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSONArray;

import java.nio.charset.StandardCharsets;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 与网联通讯解包前、解包后、组包前及组后的处理类
 * Created by
 */
public class NuccClientPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {


    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        String rcvMsg = new String(bytes, StandardCharsets.UTF_8);
        XmlTreeUtil tree = new XmlTreeUtil();
        /*删除请求的值*/
        tree.deleteXmlTreeNode(NuccTreeNodeConstant.EPCC_DGTL_ENVLP);
        tree.deleteXmlTreeNode(NuccTreeNodeConstant.EPCC_ENC_KEY);
        String srcData = pattern("(<root.*</root>)", rcvMsg);
        if (null != srcData) {
            rglog.debug("srcData:[{}]", srcData);
            tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_BLOCK, srcData);
        } else {
            rglog.error("找不到需要签名的字符串!");
            throw new Exception("找不到需要签名的字符串!");
        }

        String signData = pattern("</root>.*\\{S:(.*)?}", rcvMsg);
        if (null != signData) {
            rglog.debug("signData:[{}]", signData);
            tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN, signData);
        } else {
            rglog.error("找不到签名字符串!");
            throw new Exception("找不到签名字符串!");
        }

        return srcData.getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sign = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN);
        if (null == sign) {
            rglog.debug("无签域，不进行签名校验!");
            return 0;
        }
        /* 获取数字签名字符串 */
        String signBlock = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_BLOCK);
        rglog.debug("加签Block:<{}>", signBlock);
        rglog.debug("sign:<{}>", sign);
        CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
        CertInfo certInfo;
        /* 获取敏感信息加密证书 */
        String secPlanInfoListString = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.SEC_PLAN_INFO_LIST);
        List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
        Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(NuccParamConstant.VERIFY_CERT_TYPE)).findFirst();
        if (secPlanInfoOpt.isPresent()) {
            certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
            /* 验证签名 */
            NuccEncSignService signService = new NuccEncSignServiceImpl();
            if (signService.verifySignString(certInfo, sign, signBlock)) {
                rglog.info("签名验证成功!");
                return 0;
            } else {
                rglog.error("签名验证失败!");
                return -1;
            }
        }

        String dgtlEnvlp = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_DGTL_ENVLP);
        String msgTp = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_MSG_TP);
        //解密数字信封，获取敏感信息密钥(跳转类不需要解密，账户机构的公钥加密,账户机构解密，受理机构没有私钥)
        if (dgtlEnvlp != null &&
                !NuccTxnNumConstant.MSG_10500101.equals(msgTp) &&
                !NuccTxnNumConstant.MSG_11200101.equals(msgTp) &&
                !NuccTxnNumConstant.MSG_24200101.equals(msgTp)) {
            Optional<SecPlanInfo> secPlanInfoOptPub = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(NuccParamConstant.SIGN_CERT_TYPE)).findFirst();
            if (secPlanInfoOptPub.isPresent()) {
                certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                NuccEncSignService signService = new NuccEncSignServiceImpl();
                String encKey = signService.descryptedInfo(certInfo, dgtlEnvlp);
                xmlTreeUtil.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ENC_KEY, encKey);
            }

        }
        return -1;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        XmlTreeUtil tree = new XmlTreeUtil();
        String dateTime;
        /*报文头部分字段赋值*/
        /* 报文方向 (平台->银行为2,银行到平台为1)*/
        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_DRCTN, "11");

        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ISSR_ID, tree.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ISSR_ID));

        //设置日期时间,从系统流水号获取,撤销，退款从原流水号获取原时间
        //流水号规则：8位渠道标识 + 8位日期 + 6位时间 + 2位服务器集群标识 + 2位预留位 + 6位序号
        String seqNo = tree.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        if (seqNo == null) {
            dateTime = TimeUtil.getDateTime("yyyyMMddHHmmss");
        } else {
            dateTime = seqNo.substring(8, 22);//日期从流水号截取
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        ParsePosition pos = new ParsePosition(0);
        Date strtodate = dateFormat.parse(dateTime, pos);
        String dateStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(strtodate);
        //String time = TimeUtil.getDateTime("yyyy-MM-dd'T'HH:mm:ss");
        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SND_DT, dateStr);
        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_TRX_DT_TM, dateStr);


//todo		/* 获取敏感信息加密证书 */
        String secPlanInfoListString = tree.getXmlTreeStringValue(NuccTreeNodeConstant.SEC_PLAN_INFO_LIST);
        List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
//		Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item ->item.getSecPlanType().equals(NuccParamConstant.SIGN_CERT_TYPE)).findFirst();
//		if (secPlanInfoOpt.isPresent()){
//			CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
//			CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
//			//证书从数据库获取
//			tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_SN,certInfo.getCertDn());
//			//证书从数据库获取
//			tree.setXmlTreeObjectValue(NuccTreeNodeConstant.EPCC_PRIVATE_CER_INFO,certInfo);
//		}
        String aesKey = tree.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ENC_KEY);
        if (aesKey != null) {
            //用公钥对密钥进行加密
            Optional<SecPlanInfo> secPlanInfoOptPub = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(NuccParamConstant.VERIFY_CERT_TYPE)).findFirst();
            if (secPlanInfoOptPub.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOptPub.get().getSecPlanId() + secPlanInfoOptPub.get().getSecPlanType());
                //证书从数据库获取
                tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ENC_SN, certInfo.getCertDn());
                NuccEncSignService signService = new NuccEncSignServiceImpl();
                tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_DGTL_ENVLP, signService.encryptedInfo(certInfo, "01|" + aesKey));
            }
//
        }
        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String signBlock = StringUtil.binaryToHexString(bytes);  //StringUtil.binaryToHexString(bytes);
//		/* 获取敏感信息加密证书 */
        CertInfo certInfo = (CertInfo) xmlTreeUtil.getXmlTreeObjectValue(NuccTreeNodeConstant.EPCC_PRIVATE_CER_INFO, CertInfo.class);
        if (certInfo == null) {
            rglog.error("获取不到签名证书!");
            return bytes;
        }
//		/* 加签 */
        NuccEncSignService signService = new NuccEncSignServiceImpl();
        String signData = signService.generateSignString(certInfo, signBlock);
        String sign = String.format("{S:%s}", signData);
        String sndMsg = new String(bytes, StandardCharsets.UTF_8) + "\r\n" + sign;
//		String sndMsg = new String(bytes, StandardCharsets.UTF_8) + "\r\n";
        /* 响应信息中http头部域设置Content-Type */
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/MsgTp", xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_MSG_TP));
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/method", "POST");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Connection", "Keep-Alive");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Content-Type", "application/xml;charset=utf-8");
        xmlTreeUtil.setXmlTreeIntValue("_MESSAGEHEAD/http/Content-Length", sndMsg.getBytes(StandardCharsets.UTF_8).length);
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/ArgList", "MsgTp:Content-Type:Content-Length:method:Connection");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/OriIssrId", xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ISSR_ID));
        ;
        return sndMsg.getBytes();

    }

    private static String pattern(String regex, String str) {
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
        Matcher matcher = pattern.matcher(str);
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return null;
        }
    }
}
